﻿// // ******************************************************************
// //       /\ /|       @file       TranslationDataSynchBackgroundService.cs
// //       \ V/        @brief      await29
// //       | "")       @author     Await, 285283010@qq.com
// //       /  |
// //      /  \\        @Modified   2025-02-22 20:02
// //    *(__\_\        @Copyright  Copyright (c) , 2025-02-04 14:02 Await
// // ******************************************************************

using System.Collections.Concurrent;
using System.Threading.Channels;
using AutomaticSubtitles.Contracts.Entity;
using AutomaticSubtitles.Service.Application.Cahce.Queries;
using AutomaticSubtitles.Service.DataAccess.Model;
using AutomaticSubtitles.Service.Domain.Translate;

namespace AutomaticSubtitles.Service.BackgroundServices;

/// <summary>
///     外部翻译数据同步
/// </summary>
/// <param name="serviceProvider"></param>
public class TranslationDataSynchBackgroundService(IServiceProvider serviceProvider) : BackgroundService
{
    /// <summary>
    ///     缓存
    /// </summary>
    private static RedisClient redisClient;

    /// <summary>
    ///     日志
    /// </summary>
    private static ILogger<TranslationDataSynchBackgroundService>? logger;
    // /// <summary>
    // ///     键值对数据
    // /// </summary>
    // public static Dictionary<string, Dictionary<string, List<CacheKeyValue>>?> Translations = [];

    private ITranslateRepository repository;

    private static Channel<(string, string)>       ReceiveHost     { get; } = Channel.CreateUnbounded<(string, string)>();
    private static ConcurrentBag<(string, string)> ReceiveDataList { get; } = new();


    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using var scope = serviceProvider.CreateScope();
        var eventBus = scope.ServiceProvider.GetService<IEventBus>();
        repository = scope.ServiceProvider.GetService<ITranslateRepository>()!;
        redisClient = scope.ServiceProvider.GetService<RedisClient>()!;
        logger = scope.ServiceProvider.GetService<ILogger<TranslationDataSynchBackgroundService>>()!;
        logger.LogInformation("--后台翻译数据同步 开始");
        Init();
        _ = StatisticIpAsync(stoppingToken);
        _ = InitializeData(); //手动初始化缓存数据
        //创建两个子任务
        Task.Factory.StartNew(async () => { await RunData(eventBus!, stoppingToken); }, stoppingToken);
        Task.Factory.StartNew(async () => { await ReceiveDataAsync(stoppingToken); }, stoppingToken);
        // 使用 TaskCompletionSource 更好地控制任务生命周期
        var taskCompletionSource = new TaskCompletionSource<bool>();

        await Task.Run(async () =>
        {
            try
            {
                while (!stoppingToken.IsCancellationRequested) await Task.Delay(60 * 1000 * 60, stoppingToken);

                taskCompletionSource.SetResult(true);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "后台任务异常");
                taskCompletionSource.SetException(ex);
            }
        }, stoppingToken);
        // 等待任务完成或发生异常
        await taskCompletionSource.Task;
    }

    /// <summary>
    /// 初始化人工任务数据提交
    /// </summary>
    private void Init()
    {
        redisClient.Subscribe(nameof(TranslationDataSynchBackgroundService), async (_, x) =>
        {
            //
            if (x is not nameof(TranslationDataSynchBackgroundService)) return;
            logger.LogWarning("--收到缓存更新通知");
        });
    }

    private async Task RunData(IEventBus eventBus, CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            if (WhetherToExecuteTheTask())
            {
                await Task.Delay(60 * 1000 * 60, stoppingToken); //三十分钟更新一次
                continue;
            }

            logger?.LogInformation("--执行公共缓存数据同步任务");
            var dateTime = DateTime.Now;
            await redisClient.SetAsync(nameof(TranslationDataSynchBackgroundService), dateTime);
            await PublicDataSynchronization(eventBus, stoppingToken);
        }
    }

    /// <summary>
    ///     判断上一次执行任务时长
    /// </summary>
    /// <returns></returns>
    private bool WhetherToExecuteTheTask()
    {
        var dateTime = redisClient.Get<DateTime?>(nameof(TranslationDataSynchBackgroundService));
        if (dateTime == null) return true;
        var time = DateTime.Now;
        return time.Subtract(dateTime.Value).TotalMinutes > 50;
    }

    private async Task ReceiveDataAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            if (ReceiveDataList.IsEmpty)
            {
                await Task.Delay(30 * 1000 * 60, stoppingToken); //三十分钟更新一次
                continue;
            }

            if (ReceiveDataList.IsEmpty) continue;
            var data = new Dictionary<string, string>();
            while (ReceiveDataList.TryTake(out var iteData)) data.TryAdd(iteData.Item1, iteData.Item2);
            await Task.Factory.StartNew(async () => { await UpdateCacheTask(data); }, stoppingToken);
        }
    }

    /// <summary>
    ///     公共数据同步
    /// </summary>
    /// <param name="eventBus"></param>
    /// <param name="stoppingToken"></param>
    private async Task PublicDataSynchronization(IEventBus eventBus, CancellationToken stoppingToken)
    {
        var getPublicTranslationDataAddressQuery = new GetPublicTranslationDataAddressQuery();
        await eventBus.PublishAsync(getPublicTranslationDataAddressQuery, stoppingToken);
        //根据返回的数据 下载中的文件，并且判断文件是否是txt结尾的  如果不是就不下载
        //如果是txt结尾的 就下载下来，并且解析txt文件，并且将数据存储到数据库中
        //并且将数据存储到缓存中
        //TODO: 公共数据同步
    }

    /// <summary>
    ///     手动更新缓存数据
    /// </summary>
    /// <param name="data"></param>
    private async Task UpdateCacheTask(Dictionary<string, string> data)
    {
        foreach (var item in data)
        {
            var msg = $"--自动更新缓存数据--{item.Key}:{item.Value} 开始";
            logger!.LogInformation(msg);
            await HotWordCache(item.Key, item.Value);
            var msg2 = $"--自动更新缓存数据--{item.Key}:{item.Value} 结束";
            logger!.LogInformation(msg2);
        }
    }

    /// <summary>
    ///     初始化翻译缓存
    /// </summary>
    private async Task InitializeData()
    {
        var retrieveAllCachedData = await repository.RetrieveAllCachedData();
        foreach (var item in retrieveAllCachedData) await HotWordCache(item.Key, item.Value);
    }

    /// <summary>
    ///     热词缓存处理
    /// </summary>
    /// <param name="languageType"></param>
    /// <param name="translatedLanguageType"></param>
    private async Task HotWordCache(string languageType, string translatedLanguageType)
    {
        var retrieveDataInTheSpecifiedLanguage = await RetrieveDataInTheSpecifiedLanguage(languageType, translatedLanguageType);
        var cacheKey = $"translate:{languageType}:{translatedLanguageType}";
        await redisClient.SetAsync(cacheKey, retrieveDataInTheSpecifiedLanguage);
    }


    /// <summary>
    ///     获取指定语言的数据
    /// </summary>
    /// <param name="languageType"></param>
    /// <param name="translatedLanguageType"></param>
    /// <returns></returns>
    private async Task<List<CacheKeyValue>> RetrieveDataInTheSpecifiedLanguage(string languageType, string translatedLanguageType)
    {
        var dictionary = new Dictionary<string, bool>
        {
            { nameof(Auto_Translate.TriggerCount), true }
        };
        var paginatedListAsync =
            await repository.GetPaginatedListAsync(x => x.LanguageType == languageType && x.TranslatedLanguageType == translatedLanguageType, 0, 500, dictionary);
        var cacheValue = paginatedListAsync.Select(x => new CacheKeyValue
        {
            Id = x.Id,
            Value = x.Value,
            TranslatedValue = x.TranslatedValue
        }).ToList();
        var paginatedListAsync2 =
            await repository.GetPaginatedListAsync(x => x.TranslatedLanguageType == languageType && x.LanguageType == translatedLanguageType, 0, 500, dictionary);
        if (paginatedListAsync2.Count > 0)
        {
            var cacheKeyValues = paginatedListAsync2.Select(x => new CacheKeyValue
            {
                Id = x.Id,
                Value = x.TranslatedValue,
                TranslatedValue = x.Value
            });
            cacheValue.AddRange(cacheKeyValues);
        }
        else
        {
            var autoTranslates =
                await repository.GetPaginatedListAsync(x => x.LanguageType == languageType && x.TranslatedLanguageType == translatedLanguageType, 1, 500, dictionary);
            var cacheValue2 = autoTranslates
                .Select(x => new CacheKeyValue
                {
                    Id = x.Id,
                    Value = x.Value,
                    TranslatedValue = x.TranslatedValue
                }).ToList();
            cacheValue.AddRange(cacheValue2);
        }

        return cacheValue;
    }

    /// <summary>
    ///     数据接收
    /// </summary>
    /// <param name="stoppingToken"></param>
    private static async Task StatisticIpAsync(CancellationToken stoppingToken)
    {
        await foreach (var item in ReceiveHost.Reader.ReadAllAsync(stoppingToken))
            ReceiveDataList.Add(item);
    }


    #region 外部

    /// <summary>
    ///     缓存更新
    /// </summary>
    /// <param name="languageType"></param>
    /// <param name="translatedLanguageType"></param>
    public static void CacheUpdate(string languageType, string translatedLanguageType)
    {
        ReceiveHost.Writer.TryWrite((languageType, translatedLanguageType));
    }


    /// <summary>
    ///     获取指定语言的翻译数据
    /// </summary>
    /// <param name="languageType"></param>
    /// <param name="value"></param>
    /// <param name="translatedLanguageType"></param>
    /// <returns></returns>
    public static async Task<SubtitleSegmentationData> GetObtainTranslatedContent(string? languageType, string value, string translatedLanguageType)
    {
        //处理缓存数据，读取最热词条做缓存
        List<CacheKeyValue>? cacheValue = null;
        if (!languageType.IsNullOrWhiteSpace())
        {
            var cacheKey = $"translate:{languageType}:{translatedLanguageType}";
            cacheValue = await redisClient!.GetAsync<List<CacheKeyValue>>(cacheKey);
        }

        // 使用正则表达式拆分文本，同时保留分隔符
        var segments = Common.SplitRegex.Split(value)
            .Where(s => !string.IsNullOrEmpty(s))
            .ToList();

        var translatedSegments = new List<string>();
        var updateTranslatedId = new List<string>();
        var untranslatedSegments = new Dictionary<int, string>();
        var allTranslated = true;

        for (var i = 0; i < segments.Count; i++)
        {
            var segment = segments[i];

            if (segment.IsNullOrEmpty()) continue;
            // 如果是分隔符，直接添加
            if (Common.SplitRegex.IsMatch(segment))
            {
                translatedSegments.Add(segment);
                continue;
            }

            // 处理需要翻译的文本段
            var isTranslated = false;
            if (cacheValue?.Any() == true)
            {
                var cachedTranslation = cacheValue.FirstOrDefault(x =>
                    x.Value.Equals(segment, StringComparison.OrdinalIgnoreCase));

                if (cachedTranslation != null)
                {
                    logger?.LogInformation($"--从缓存中读取翻译: {segment}--》{cachedTranslation.TranslatedValue}");
                    translatedSegments.Add(cachedTranslation.TranslatedValue);
                    updateTranslatedId.Add(cachedTranslation.Id);
                    isTranslated = true;
                }
            }

            if (isTranslated) continue;
            allTranslated = false;
            untranslatedSegments.Add(i, segment);
            translatedSegments.Add(segment); // 暂时保持原文
        }

        var data = new SubtitleSegmentationData
        {
            TranslatedSegments = translatedSegments,
            UntranslatedSegments = untranslatedSegments,
            OriginalSegments = segments,
            UpdateTranslatedID = updateTranslatedId,
            AllTranslated = allTranslated
        };
        return data;
    }

    #endregion
}